home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / manual-p / man_db-2.000 / man_db-2 / man_db-2.3.10 / lib / cleanup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-04  |  5.3 KB  |  239 lines

  1. /* cleanup.c -- simple dynamic cleanup function management
  2.    Copyright (C) 1995 Markus Armbruster
  3.  
  4.    This program is free software; you can redistribute it and/or
  5.    modify it under the terms of the GNU General Library Public License
  6.    as published by the Free Software Foundation; either version 2, or
  7.    (at your option) any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; see the file COPYING.LIB.  If not, write
  16.    to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
  17.    02139, USA.  */
  18.  
  19. #ifdef HAVE_CONFIG_H
  20. #  include "config.h"
  21. #endif /* HAVE_CONFIG_H */
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>        /* SunOS's loosing assert.h needs it */
  25. #include <assert.h>
  26. #include <signal.h>
  27. #if defined(HAVE_UNISTD_H)
  28. #  include <unistd.h>
  29. #endif
  30.  
  31. #include "manconfig.h"        /* for FATAL */
  32. #include "cleanup.h"
  33.  
  34.  
  35. #ifndef HAVE_ATEXIT
  36. #  ifdef HAVE_ON_EXIT
  37. #    define atexit(fun) (on_exit ((void (*)())fun, NULL))
  38. #  else
  39. #    error need either atexit() or on_exit()
  40. /* If necessary we could dummify the whole module in this case */
  41. #  endif
  42. #endif
  43.  
  44.  
  45.  
  46. /* Dealing with signals */
  47.  
  48.  
  49. /* saved signal actions */
  50. static struct sigaction saved_hup_action;
  51. static struct sigaction saved_int_action;
  52. static struct sigaction saved_term_action;
  53.  
  54.  
  55. /* Call do_cleanups(), then reraise signal with default handler. */
  56. static void
  57. sighandler (int signo)
  58. {
  59.   struct sigaction act;
  60.   sigset_t set;
  61.  
  62.   do_cleanups ();
  63.  
  64.   /* set default signal action */
  65.   act.sa_handler = SIG_DFL;
  66.   sigemptyset (&act.sa_mask);
  67.   act.sa_flags = 0;
  68.   if (sigaction (SIGINT, &act, NULL)) {
  69.     /* should not happen */
  70.     _exit (FATAL);        /* exit() is taboo from signal handlers! */
  71.   }
  72.  
  73.   /* unmask signo */
  74.   if (   sigemptyset (&set)
  75.       || sigaddset (&set, signo)
  76.       || sigprocmask (SIG_UNBLOCK, &set, NULL)) {
  77.     /* shouldn't happen */
  78.     _exit (FATAL);        /* exit() is taboo from signal handlers! */
  79.   }
  80.  
  81.   /* signal has now default action and is unmasked,
  82.      reraise it to terminate program abnormally */
  83.   kill (getpid(), signo);
  84.   abort();
  85. }
  86.  
  87.  
  88. /* Save signo's current action to oldact, if it's handler is SIG_DFL
  89.    install sighandler, return 0 on success, -1 on failure. */
  90. static int
  91. trap_signal (int signo, struct sigaction *oldact)
  92. {
  93.   if (sigaction (signo, NULL, oldact)) {
  94.     return -1;
  95.   }
  96.  
  97.   if (oldact->sa_handler == SIG_DFL) {
  98.     struct sigaction act;
  99.  
  100.     act.sa_handler = sighandler;
  101.     sigemptyset (&act.sa_mask);
  102.     act.sa_flags = 0;
  103.     return sigaction (signo, &act, oldact);
  104.   }
  105.  
  106.   return 0;
  107. }
  108.  
  109.  
  110. /* Trap some abnormal exits to call do_cleanups(). */
  111. static int
  112. trap_abnormal_exits (void)
  113. {
  114.   if (   trap_signal (SIGHUP, &saved_hup_action)
  115.       || trap_signal (SIGINT, &saved_int_action)
  116.       || trap_signal (SIGTERM, &saved_term_action))
  117.     return -1;
  118.   return 0;
  119. }
  120.  
  121.  
  122. /* Restore signo's action from oldact if it's current handler is
  123.    sighandler, return 0 on success, -1 on failure. */
  124. static int
  125. untrap_signal (int signo, struct sigaction *oldact)
  126. {
  127.   struct sigaction act;
  128.   if (sigaction (signo, NULL, &act)) {
  129.     return -1;
  130.   }
  131.  
  132.   if (act.sa_handler == sighandler) {
  133.     return sigaction (signo, oldact, NULL);
  134.   }
  135.  
  136.   return 0;
  137. }
  138.  
  139.  
  140. /* Undo a previous trap_abnormal_exits(). */
  141. static int
  142. untrap_abnormal_exits (void)
  143. {
  144.   if (  untrap_signal (SIGHUP, &saved_hup_action)
  145.       | untrap_signal (SIGINT, &saved_int_action)
  146.       | untrap_signal (SIGTERM, &saved_term_action))
  147.     return -1;
  148.   return 0;
  149. }
  150.  
  151.  
  152.  
  153. typedef struct {
  154.   cleanup_fun fun;
  155.   void *arg;
  156. } slot;
  157.  
  158. static slot *stack = NULL;    /* stack of cleanup functions */
  159. static unsigned nslots = 0;    /* #slots in stack */
  160. static unsigned tos = 0;    /* top of stack, 0 <= tos <= nslots */
  161.  
  162. /* Call cleanup functions in stack from from top to bottom,
  163.    Automatically called on program termination via exit(3) or default
  164.    action for SIGHUP, SIGINT or SIGTERM. */
  165. void
  166. do_cleanups (void)
  167. {
  168.   unsigned i;
  169.  
  170.   assert (tos <= nslots);
  171.   for (i = tos;  i > 0;  --i) {
  172.     stack[i-1].fun (stack[i-1].arg);
  173.   }
  174. }
  175.  
  176.  
  177. /* Push a cleanup function on the cleanup stack,
  178.    return 0 on success, -1 on failure.
  179.    Caution: the cleanup function may be called from signal handlers. */
  180. int
  181. push_cleanup (cleanup_fun fun, void *arg)
  182. {
  183.   static int handler_installed = 0;
  184.  
  185.   assert (tos <= nslots);
  186.  
  187.   if (!handler_installed) {
  188.     if (atexit (do_cleanups))
  189.       return -1;
  190.     handler_installed = 1;
  191.   }
  192.  
  193.   if (tos == nslots) {
  194.     /* stack is full, allocate another slot */
  195.     /* stack is not expected to grow much, otherwise we would double it */
  196.     slot *new_stack;
  197.  
  198.     if (stack) {
  199.       new_stack = xrealloc (stack, (nslots+1)*sizeof(slot));
  200.     } else {
  201.       new_stack = xmalloc ((nslots+1)*sizeof(slot));
  202.     }
  203.       
  204.     if (!new_stack) return -1;
  205.     stack = new_stack;
  206.     ++nslots;
  207.   }
  208.  
  209.   assert (tos < nslots);
  210.   stack[tos].fun = fun;
  211.   stack[tos].arg = arg;
  212.   ++tos;
  213.  
  214.  
  215.   trap_abnormal_exits();
  216.  
  217.   return 0;
  218. }
  219.  
  220.  
  221. /* Pop top cleanup function from the cleanup stack. */
  222. void
  223. pop_cleanup (void)
  224. {
  225.   assert (tos > 0);
  226.   --tos;
  227.  
  228.   if (tos == 0) untrap_abnormal_exits();
  229. }
  230.  
  231.  
  232. /* Pop all cleanup functions from the cleanup stack. */
  233. void
  234. pop_all_cleanups (void)
  235. {
  236.   tos = 0;
  237.   untrap_abnormal_exits();
  238. }
  239.